#!/usr/bin/env bash
# plimit
# Copyright (C) 2006-2008 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# plimit reports all resource limits by the process id.
#
# plimit is not a port of Solaris' plimit tool. It was written based on the
# example output in http://safari.oreilly.com/0131482092/ch02lev1sec6. I do
# not intend to write the "sets per-process limits on a running process"
# feature. If you are interested, write a patch, and drop me an email.
#
# Last updated: Sun Jan 20 12:49:26 SGT 2008
#

if [ $# -eq 0 ]; then
	cat >&2 <<-EOF
	usage:  plimit pid ...
	  (report all resource limits of each process)
	EOF
	exit
fi

pid=$1

/usr/bin/env stap -g -e '

function get_task_struct:long (pid:long) %{
	struct task_struct *p;

	rcu_read_lock();
	p = find_task_by_pid((int)THIS->pid);
	rcu_read_unlock();

	THIS->__retvalue = (long)kread(&p);
	CATCH_DEREF_FAULT();
%}

function get_task_info:string (task:long) %{
	int i;
	char pid[10], comm[TASK_COMM_LEN];
	struct task_struct *p = (struct task_struct *)((long)THIS->task);
	for (i = 0; i < TASK_COMM_LEN; ++i)
		comm[i] = kread(&p->comm[i]);
	sprintf(pid, "%d:", kread(&p->pid));
	snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-6s %s", pid, comm);
	CATCH_DEREF_FAULT();
%}

function getrlimit:string (task:long, rlim:long) %{
	struct task_struct *p = (struct task_struct *)((long)THIS->task);
	long int cur = kread(&p->signal->rlim[THIS->rlim].rlim_cur);
	long int max = kread(&p->signal->rlim[THIS->rlim].rlim_max);
	
	if (cur == -1 && max == -1)
		strcat(THIS->__retvalue, "unlimited  unlimited");
	else if (cur == -1)
		snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9s  %-9ld", "unlimited", max);
	else if (max == -1)
		snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9ld  %-9s", cur, "unlimited");
	else
		snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9ld  %-9ld", cur, max);
	CATCH_DEREF_FAULT();
%}

probe begin
{
	pid = '$pid'
	task = get_task_struct(pid)
     	printf("%s\n", get_task_info(task))

	/* include/asm-generic/resource.h */
   	printf(" resource                    current    maximum\n")
	printf("coredump(blocks)            %s\n", getrlimit(task, 4))
	printf("data(bytes)                 %s\n", getrlimit(task, 2))
	printf("max nice                    %s\n", getrlimit(task, 13))
	printf("file size(blocks)           %s\n", getrlimit(task, 1))
	printf("pending signals             %s\n", getrlimit(task, 11))
	printf("max locked memory(bytes)    %s\n", getrlimit(task, 8))
	printf("max memory size(bytes)      %s\n", getrlimit(task, 5))
	printf("open files                  %s\n", getrlimit(task, 7))
	printf("POSIX message queues(bytes) %s\n", getrlimit(task, 12))
	printf("max rt priority             %s\n", getrlimit(task, 14))
	printf("stack size(bytes)           %s\n", getrlimit(task, 3))
	printf("cpu time(seconds)           %s\n", getrlimit(task, 0))
	printf("max user processes          %s\n", getrlimit(task, 6))
	printf("virtual memory(bytes)       %s\n", getrlimit(task, 9))
	printf("file locks                  %s\n", getrlimit(task, 10))

	exit()
}
'
